#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <functional>
#include <sys/epoll.h>
#include "log.hpp"
#include "sock.hpp"
using namespace std;

namespace epoll_ns
{
    class epollServer
    {
        static const uint16_t gport = 8080;
        static const int gsize = 128;
        static const int defaultval = -1;
        static const int gnum = 64;
        using func_t = function<string (const string&)>;
    public:
        epollServer(func_t f, uint16_t port = gport, int num = gnum)
            :_func(f), _port(port), _listensock(-1), _epfd(-1), _num(num), _revts(nullptr)
        {}
        void initServer()
        {
            // 1. 创建socket
            _listensock = sock::Socket();
            sock::Bind(_listensock, _port);
            sock::Listen(_listensock);
            // 2. 创建epoll模型
            _epfd = epoll_create(gsize);
            if (_epfd < 0)
            {
                logMessage(FATAL, "epoll create errno :%s", strerror(errno));
                exit(EPOLL_CREATE_ERR);
            }
            // 3. 添加_listensock到epoll中
            struct epoll_event ev;
            // ev.events = EPOLLIN ;    //默认是LT模式-水平触发
            ev.events = EPOLLIN | EPOLLET;  //设置成ET模式-边缘触发
            ev.data.fd = _listensock;   //当事件就绪，被重新捞取上来时，我们要知道是哪一个fd就绪了
            epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);

            // 4. 申请就绪事件的空间
            _revts = new struct epoll_event[_num];

            logMessage(NORMAL, "init server success");
        }
        void HandlerEvent(int readyNum)
        {
            for(int i = 0; i < readyNum; ++i)
            {
                uint32_t events =  _revts[i].events;
                int sock = _revts[i].data.fd;

                if(sock == _listensock && (events & EPOLLIN))   //_listensock读时间就绪，获取新连接
                {
                    string clientip;
                    uint16_t clientport = 0;
                    int fd = sock::Accept(sock, &clientip, &clientport);
                    if(fd < 0)
                    {
                        logMessage(WARNING, "accept falid");
                        continue;
                    }
                    // 获取fd成功，可以直接读取吗？ 不能
                    struct epoll_event ev;
                    ev.data.fd = fd;
                    ev.events = EPOLLIN;
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);

                }
                else if(events & EPOLLIN)   //普通读时间就绪
                {
                    // 这里的读是有问题的，因为tcp是字节流的，我们并不知道读上来的是否是完整的报文，
                    // 用循环读取也有问题，我们知道第一次读是就绪的，但是下一次是否是就绪的呢？
                    char buffer[1024];
                    int n = recv(sock, buffer, sizeof(buffer)-1, 0);
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        logMessage(NORMAL, "client# %s", buffer);
                        string responce = _func(buffer);
                        send(sock, responce.c_str(), responce.size(), 0);
                    }
                    else if(n == 0)
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(NORMAL, "client quit!");
                    }
                    else
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(ERROR, "recv falid, code:%d, error:%s",errno,strerror(errno));
                    }
                }
            } 

        }
        void start()
        {
            int timeout = -1;
            for (;;)
            {
                int n = epoll_wait(_epfd, _revts, _num, timeout);
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "timeout...");
                    break;
                case -1:
                    logMessage(WARNING, "epoll_wait falid, code:%d, error:%s",errno,strerror(errno));
                    break;
                default:
                    logMessage(NORMAL, "have event ready");
                    // HandlerEvent(n);
                    break;
                }
            }
        }
        ~epollServer()
        {
            if (_listensock != defaultval)
                close(_listensock);
            if (_epfd != defaultval)
                close(_epfd);
            if (_revts)
                delete[] _revts;
        }

    private:
        uint16_t _port;
        int _listensock;
        int _epfd;
        struct epoll_event *_revts;
        int _num;
        func_t _func;
    };
}